
package com.huaweicloud.saaslanding.install.applicationservice.impl;

import com.huaweicloud.saaslanding.basic.database.mybatis.conditions.query.QueryWrap;
import com.huaweicloud.saaslanding.basic.utils.EncryptionUtil;
import com.huaweicloud.saaslanding.dao.common.entity.cloudservice.EndpointInfo;
import com.huaweicloud.saaslanding.dao.common.entity.cloudservice.IamAccountInfo;
import com.huaweicloud.saaslanding.dao.common.entity.security.WorkSecretKey;
import com.huaweicloud.saaslanding.dao.common.repository.cloudservice.EndpointInfoBaseMapper;
import com.huaweicloud.saaslanding.dao.common.repository.cloudservice.IamAccountInfoBaseMapper;
import com.huaweicloud.saaslanding.dao.common.repository.security.WorkSecretKeyBaseMapper;
import com.huaweicloud.saaslanding.dao.common.repository.tenant.TenantBaseMapper;
import com.huaweicloud.saaslanding.huawei.iam.api.IamApi;
import com.huaweicloud.saaslanding.huawei.smn.SmnApi;
import com.huaweicloud.saaslanding.huawei.smn.constant.BuiltInMessageTemplate;
import com.huaweicloud.saaslanding.huawei.smn.enumeration.ProtocolType;
import com.huaweicloud.saaslanding.huawei.smn.model.ListSubscriptionItem;
import com.huaweicloud.saaslanding.huawei.smn.model.ListTopicItem;
import com.huaweicloud.saaslanding.huawei.smn.model.MessageTemplate;
import com.huaweicloud.saaslanding.huawei.smn.request.CreateMessageTemplateRequestBody;
import com.huaweicloud.saaslanding.huawei.smn.request.QueryMessageTemplateListParam;
import com.huaweicloud.saaslanding.huawei.smn.request.QuerySubscriptionParam;
import com.huaweicloud.saaslanding.huawei.smn.request.QueryTopicParam;
import com.huaweicloud.saaslanding.huawei.smn.request.QueryTopicSubscriptionParam;
import com.huaweicloud.saaslanding.huawei.smn.response.MessageTemplateListResponse;
import com.huaweicloud.saaslanding.huawei.smn.response.SubscriptionResponse;
import com.huaweicloud.saaslanding.huawei.smn.response.TopicListResponse;
import com.huaweicloud.saaslanding.huawei.smn.response.TopicSubscriptionResponse;
import com.huaweicloud.saaslanding.install.applicationservice.SmnService;

import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 功能描述
 *
 * @since 2022-12-05
 */
@Slf4j
@Service
public class SmnServiceImpl implements SmnService {
    private static final int MAX_QUERY = 100;

    private static final int DEFAULT_OFFSET = 0;

    @Resource
    private IamAccountInfoBaseMapper iamAccountInfoBaseMapper;

    @Resource
    private WorkSecretKeyBaseMapper workSecretKeyBaseMapper;

    @Resource
    private EndpointInfoBaseMapper endpointInfoBaseMapper;

    @Resource
    private TenantBaseMapper tenantBaseMapper;

    @Resource
    private SmnApi smnApi;

    @Value("${saaslanding.platformAppName}")
    private String platformAppName;

    /**
     * 删除所有订阅
     */
    @Override
    public void clearSubscription() {
        log.info("删除所有订阅...");

        EndpointInfo basicInfo = endpointInfoBaseMapper.selectOne(new QueryWrap<EndpointInfo>().eq("is_del", 0));
        String smnEndpoint = basicInfo.getSmnEndpoint();
        String projectId = basicInfo.getProjectId();
        Map<String, String> headers = getIamHeader(projectId);
        if (CollectionUtils.isEmpty(headers)) {
            log.info("salt不存在，无需清理订阅信息。");
            return;
        }

        SubscriptionResponse response = smnApi.querySubscriptionList(smnEndpoint, headers, projectId,
            new QuerySubscriptionParam().setLimit(MAX_QUERY).setOffset(DEFAULT_OFFSET));

        for (ListSubscriptionItem subscription : response.getSubscriptions()) {
            smnApi.deleteSubscription(smnEndpoint, headers, projectId, subscription.getSubscriptionUrn());
        }

        Integer total = response.getSubscriptionCount();
        total -= MAX_QUERY;
        while (total > 0) {
            // 查询到订阅后立即删除, 所以每次查询的偏移量都是0
            response = smnApi.querySubscriptionList(smnEndpoint, headers, projectId,
                new QuerySubscriptionParam().setLimit(MAX_QUERY).setOffset(DEFAULT_OFFSET));
            total -= MAX_QUERY;

            for (ListSubscriptionItem subscription : response.getSubscriptions()) {
                smnApi.deleteSubscription(smnEndpoint, headers, projectId, subscription.getSubscriptionUrn());
            }
        }

        log.info("所有订阅删除成功.");
    }

    /**
     * 删除所有主题
     */
    @Override
    public void clearTopic() {
        log.info("删除所有主题...");

        EndpointInfo basicInfo = endpointInfoBaseMapper.selectOne(new QueryWrap<EndpointInfo>().eq("is_del", 0));
        String smnEndpoint = basicInfo.getSmnEndpoint();
        String projectId = basicInfo.getProjectId();
        Map<String, String> headers = getIamHeader(projectId);
        if (CollectionUtils.isEmpty(headers)) {
            log.info("salt不存在，无需清理主题信息。");
            return;
        }

        TopicListResponse response = smnApi.queryTopicList(smnEndpoint, headers, projectId,
            new QueryTopicParam().setLimit(MAX_QUERY).setOffset(DEFAULT_OFFSET));
        for (ListTopicItem topic : response.getTopics()) {
            smnApi.deleteTopic(smnEndpoint, headers, projectId, topic.getTopicUrn());
        }

        Integer total = response.getTopicCount();
        total -= MAX_QUERY;
        while (total > 0) {
            response = smnApi.queryTopicList(smnEndpoint, headers, projectId,
                new QueryTopicParam().setLimit(MAX_QUERY).setOffset(DEFAULT_OFFSET));
            total -= MAX_QUERY;

            for (ListTopicItem topic : response.getTopics()) {
                smnApi.deleteTopic(smnEndpoint, headers, projectId, topic.getTopicUrn());
            }
        }

        log.info("所有主题删除成功.");
    }

    /**
     * 删除当前环境的主题和订阅
     */
    @Override
    public void clearCurrentEnvironment() {
        log.info("删除<{}>环境的所有主题和订阅...", platformAppName);

        EndpointInfo basicInfo = endpointInfoBaseMapper.selectOne(new QueryWrap<EndpointInfo>().eq("is_del", 0));
        String smnEndpoint = basicInfo.getSmnEndpoint();
        String projectId = basicInfo.getProjectId();
        Map<String, String> headers = getIamHeader(projectId);
        if (CollectionUtils.isEmpty(headers)) {
            log.info("salt不存在，无需清理主题和订阅。");
            return;
        }

        List<String> tenantCodeList = tenantBaseMapper.getTenantCodeList();
        for (String tenantCode : tenantCodeList) {
            deleteByTenant(tenantCode, smnEndpoint, projectId, headers);
        }
    }

    /**
     * 创建默认消息模板
     */
    @Override
    public void createDefaultMessageTemplate() {
        log.info("开始创建默认消息模板...");

        EndpointInfo basicInfo = endpointInfoBaseMapper.selectOne(new QueryWrap<EndpointInfo>().eq("is_del", 0));
        String smnEndpoint = basicInfo.getSmnEndpoint();
        String projectId = basicInfo.getProjectId();
        Map<String, String> headers = getIamHeader(projectId);

        // 添加后缀以区分不同环境
        for (Map.Entry<String, String> entry : BuiltInMessageTemplate.DEFAULT_MESSAGE_TEMPLATE.entrySet()) {
            smnApi.createMessageTemplate(smnEndpoint, headers, projectId,
                new CreateMessageTemplateRequestBody().setProtocol(ProtocolType.DEFAULT.getProtocol())
                    .setMessageTemplateName(entry.getKey() + '-' + platformAppName)
                    .setContent(entry.getValue()));
        }

        log.info("创建默认消息模板成功.");
    }

    /**
     * 删除默认消息模板
     */
    @Override
    public void deleteDefaultMessageTemplate() {
        log.info("开始删除默认消息模板...");

        EndpointInfo basicInfo = endpointInfoBaseMapper.selectOne(new QueryWrap<EndpointInfo>().eq("is_del", 0));
        String smnEndpoint = basicInfo.getSmnEndpoint();
        String projectId = basicInfo.getProjectId();
        Map<String, String> headers = getIamHeader(projectId);
        if (CollectionUtils.isEmpty(headers)) {
            log.info("salt不存在，无需清理消息模板。");
            return;
        }

        // 添加后缀以区分不同环境
        List<String> messageTemplateIdList = new ArrayList<>();
        for (String name : BuiltInMessageTemplate.DEFAULT_MESSAGE_TEMPLATE.keySet()) {
            MessageTemplateListResponse response = smnApi.queryMessageTemplateList(smnEndpoint, headers, projectId,
                new QueryMessageTemplateListParam().setMessageTemplateName(name + '-' + platformAppName));

            messageTemplateIdList
                .addAll(response.getMessageTemplates().stream().map(MessageTemplate::getMessageTemplateId).toList());
        }

        for (String messageTemplateId : messageTemplateIdList) {
            smnApi.deleteMessageTemplate(smnEndpoint, headers, projectId, messageTemplateId);
        }

        log.info("删除默认消息模板成功.");
    }

    /**
     * 删除单个租户的主题及所有订阅
     *
     * @param tenantCode 租户编码
     * @param smnEndpoint SMN端点
     * @param projectId 项目ID
     * @param headers 请求头
     */
    private void deleteByTenant(String tenantCode, String smnEndpoint, String projectId, Map<String, String> headers) {
        TopicListResponse topicListResponse = smnApi.queryTopicList(smnEndpoint, headers, projectId,
            new QueryTopicParam().setName(tenantCode).setLimit(1).setOffset(0));

        if (topicListResponse.getTopicCount() == 0) {
            log.info("没有找到租户<{}>的主题, 跳过当前租户.", tenantCode);
            return;
        }

        String topicUrn = topicListResponse.getTopics().get(0).getTopicUrn();
        TopicSubscriptionResponse response = smnApi.queryTopicSubscription(smnEndpoint, headers, projectId, topicUrn,
            new QueryTopicSubscriptionParam().setLimit(MAX_QUERY).setOffset(DEFAULT_OFFSET));

        for (ListSubscriptionItem subscription : response.getSubscriptions()) {
            smnApi.deleteSubscription(smnEndpoint, headers, projectId, subscription.getSubscriptionUrn());
        }

        Integer total = response.getSubscriptionCount();
        total -= MAX_QUERY;
        while (total > 0) {
            // 查询到订阅后立即删除, 所以每次查询的偏移量都是0
            response = smnApi.queryTopicSubscription(smnEndpoint, headers, projectId, topicUrn,
                new QueryTopicSubscriptionParam().setLimit(MAX_QUERY).setOffset(DEFAULT_OFFSET));
            total -= MAX_QUERY;

            for (ListSubscriptionItem subscription : response.getSubscriptions()) {
                smnApi.deleteSubscription(smnEndpoint, headers, projectId, subscription.getSubscriptionUrn());
            }
        }

        smnApi.deleteTopic(smnEndpoint, headers, projectId, topicUrn);
    }

    /**
     * 获取IAM header
     *
     * @param projectId 项目ID
     * @return IAM header
     */
    private Map<String, String> getIamHeader(String projectId) {
        WorkSecretKey platformWorkSecretKey = workSecretKeyBaseMapper.getPlatformSalt();
        if (platformWorkSecretKey == null) {
            return null;
        }

        String pwdSalt =
            EncryptionUtil.decrypt(platformWorkSecretKey.getPwdSalt(), platformWorkSecretKey.getPassword());

        IamAccountInfo iamInfo = iamAccountInfoBaseMapper.getIamInfo();
        iamInfo.setPassword(EncryptionUtil.decrypt(pwdSalt, iamInfo.getPassword()));

        return IamApi.getIamHeader(iamInfo.getEndpoint(), iamInfo.getDomainName(), iamInfo.getIamName(),
            iamInfo.getPassword(), projectId);
    }
}
